﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BacteriaSimulation.Simulation
{
    public class CannibalBacteriumStrategy : BacteriumSimulationStrategy
    {
        protected Vector2D NewSpeed = null;

        public CannibalBacteriumStrategy()
        {
            this.diet = DietType.CARNIVORE;
        }

        public override void PerformStrategy(Bacterium bacterium, SimulationEnvironment env)
        {
            env.UngrowBacterium(bacterium);

            if (bacterium.Energy <= 0)
            {
                bacterium.State = BacteriumState.DEAD;
                return;
            }

            // Now the bacterium takes a look at the environment next to him
            View view = bacterium.See();
            Bacterium slowestBacterium = null;
            Bacterium nearestBacterium = null;
            Double slowestSquareSpeedModule = 0;
            double nearestSquareDistance = double.MaxValue;
            List<IndexGridCell>.Enumerator enumerator = view.GetEnumerator();
            while (enumerator.MoveNext())
            {
                foreach(Bacterium prey in enumerator.Current.Bacteria)
                {
                    if (prey == bacterium || prey.Diet == DietType.CARNIVORE)
                    {
                        continue;
                    }
                    double squareSpeedModule = Math.Pow(prey.Speed.XComponent, 2) + Math.Pow(prey.Speed.YComponent, 2);
                    if (slowestBacterium == null || squareSpeedModule < slowestSquareSpeedModule)
                    {
                        slowestBacterium = prey;
                        slowestSquareSpeedModule = squareSpeedModule;
                    }
                    double squareDistance =  SimulationPoint.SquareDistance(bacterium.Position, prey.Position);
                    if (nearestBacterium == null || squareDistance < nearestSquareDistance)
                    {
                        nearestBacterium = prey;
                        nearestSquareDistance = squareDistance;
                    }
                }
            }

            //if (slowestBacterium != null)
            //{
            //    double xDistance = slowestBacterium.Position.X - bacterium.Position.X;
            //    double yDistance = slowestBacterium.Position.Y - bacterium.Position.Y;

            //    double distance = SimulationPoint.Distance(bacterium.Position, slowestBacterium.Position);
            //    double speedModule = Math.Sqrt((bacterium.Speed.XComponent * bacterium.Speed.XComponent) + (bacterium.Speed.YComponent * bacterium.Speed.YComponent));
            //    double ratio = speedModule / distance;
            //    this.NewSpeed = new Vector2D(xDistance * ratio, yDistance * ratio);
            //}

            if (nearestBacterium != null)
            {
                //double xDistance = nearestBacterium.Position.X - bacterium.Position.X;
                //double yDistance = nearestBacterium.Position.Y - bacterium.Position.Y;

                //double distance = SimulationPoint.Distance(bacterium.Position, nearestBacterium.Position);
                //double speedModule = Math.Sqrt((bacterium.Speed.XComponent * bacterium.Speed.XComponent) + (bacterium.Speed.YComponent * bacterium.Speed.YComponent));
                //double ratio = speedModule / distance;
                //this.NewSpeed = new Vector2D(xDistance * ratio, yDistance * ratio);
                ////////////////////////////////////////////////////////////////////////////////////////////////////

                //bacterium.AccelerationDirection = new UnitVector2D(nearestBacterium.X - bacterium.X, nearestBacterium.Y - bacterium.Y);
                ////////////////////////////////////////////////////////////////////////////////////////////////////

                // vector connectig this bacterium with the nearest:
                Vector2D connection = new Vector2D(nearestBacterium.X - bacterium.X, nearestBacterium.Y - bacterium.Y);
                //double angleCosine = (bacterium.Speed.XComponent * connection.XComponent + bacterium.Speed.YComponent * connection.YComponent) / bacterium.Speed.GetMagnitude() * connection.GetMagnitude();
                Vector2D rightPerpendicular = new Vector2D(connection.YComponent, -1 * connection.XComponent);
                // The value of dotProduct tells if the angle between connection and bacterium.Speed (the current direction of the bacterium)
                // is positive or negative
                double dotProduct = rightPerpendicular.XComponent * bacterium.Speed.XComponent + rightPerpendicular.YComponent * bacterium.Speed.YComponent;
                if (dotProduct < 0 + env.Epsilon)
                {
                    // the angle is negative: bacterium must turn right. the new acceleration is along the right perpendicular to the 
                    // current speed
                    bacterium.AccelerationDirection = new UnitVector2D(bacterium.Speed.YComponent, -1 * bacterium.Speed.XComponent);
                }
                else if (dotProduct > 0 + env.Epsilon)
                {
                    // the angle is positive: bacterium must turn left. the new acceleration is along the left perpendicular to the 
                    // current speed
                    bacterium.AccelerationDirection = new UnitVector2D(-1 * bacterium.Speed.YComponent, bacterium.Speed.XComponent);
                }
                else
                {
                    // the current direction is just good to get the prey
                    bacterium.AccelerationDirection = new UnitVector2D(connection.XComponent, connection.YComponent);
                }
            }
            else
            {
                bacterium.AccelerationDirection = new UnitVector2D(-bacterium.Speed.XComponent, -bacterium.Speed.YComponent);
            }

            //if (NewSpeed != null)
            //{
            //    bacterium.Speed = NewSpeed;
            //    NewSpeed = null;
            //}
        }

        public override void WallCollisionDetected(Bacterium bacterium, WALL_COLLISION_TYPE collisionType, SimulationEnvironment env)
        {
            switch (collisionType)
            {
                case WALL_COLLISION_TYPE.BOTTOM:
                    {
                        bacterium.Speed.YComponent *= -1;
                        bacterium.AccelerationDirection.YComponent *= -1;
                        break;
                    }
                case WALL_COLLISION_TYPE.RIGHT:
                    {
                        bacterium.Speed.XComponent *= -1;
                        bacterium.AccelerationDirection.XComponent *= -1;
                        break;
                    }
                case WALL_COLLISION_TYPE.TOP:
                    {
                        bacterium.Speed.YComponent *= -1;
                        bacterium.AccelerationDirection.YComponent *= -1;
                        break;
                    }
                case WALL_COLLISION_TYPE.LEFT:
                    {
                        bacterium.Speed.XComponent *= -1;
                        bacterium.AccelerationDirection.XComponent *= -1;
                        break;
                    }
            }
        }

        public override void BacteriumCollisionDetected(Bacterium bacterium, Bacterium collidedBacterium, SimulationEnvironment env)
        {
            if (bacterium.State != BacteriumState.DEAD
                && collidedBacterium.Diet == DietType.HERBIVORE 
                && collidedBacterium.State != BacteriumState.DEAD
                && collidedBacterium.Energy < bacterium.Energy)
            {
                collidedBacterium.State = BacteriumState.DEAD;
                bacterium.EatAndGrow(collidedBacterium);
            }
        }
    }
}
